# encoding:utf-8
from CurrApk import *

import atx
import time


class Agt(object):
    def __init__(self, temp_path, result_path, click_delay=5):
        set_log_path(result_path)
        self.atx = self.init_atx()
        self.device_resolution = self.get_device_resolution()
        self.temp_path = temp_path
        self.result_path = result_path
        self.click_delay = click_delay
        self.curr_apk = None

    def set_curr_apk(self, apk_path):
        self.curr_apk = CurrentApk(apk_path, self.temp_path, unzip=False)

    def init_atx(self):
        try:
            d = atx.connect(os.getenv("SERIAL"))
            logging.info('Initiate atx success !')
            return d
        except:
            logging.error('Initiate atx fail !')
            return False

    def install_apk(self):
        try:
            self.atx.adb_cmd(['install', self.curr_apk.apk_path])
            logging.info('Install apk success !')
            return True
        except:
            logging.error('Install apk fail !')
            return False

    def start_app(self, delay=5):
        try:
            self.atx.start_app(self.curr_apk.package_name)
            logging.info('Start apk success !')
            time.sleep(delay)
            return True
        except:
            logging.error('Start apk fail !')
            return False

    def stop_app(self):
        self.atx.stop_app(self.curr_apk.package_name, clear=True)
        time.sleep(1)

    def restart_app(self, delay):
        self.stop_app()
        self.start_app(delay)

    def uninstall_app(self):
        os.popen('adb uninstall ' + self.curr_apk.package_name)

    def get_device_resolution(self):
        device_INFO = os.popen('adb shell dumpsys window displays').read()
        device_resolution = device_INFO[device_INFO.find("cur=") + 4:device_INFO.find("app=") - 1].split('x')
        return device_resolution

    def get_current_activity(self):
        apk_INFO = os.popen('adb shell dumpsys activity | findstr "mFocusedActivity"').read()
        activity = apk_INFO[apk_INFO.find("/") + 1:apk_INFO.rfind(" ")]
        return activity

    def get_current_package(self):
        apk_INFO = os.popen('adb shell dumpsys activity | findstr "mFocusedActivity"').read()
        package = apk_INFO[apk_INFO.rfind(' ', 0, apk_INFO.find("/") - 1) + 1:apk_INFO.find("/")]
        return package

    def check_current_app(self):
        if self.curr_apk.package_name == self.get_current_package():
            return True
        else:
            return False

    def get_name_time(self):
        t = time.localtime(time.time())
        return str(t.tm_year) + '-' + str(t.tm_mon) + '-' + str(t.tm_mday) + '_' + str(t.tm_hour) + str(t.tm_min) + str(
            t.tm_sec)

    def take_screenshot(self, output=True):
        time_name = self.get_name_time()
        try:
            if output:
                screenshot_path = self.result_path + '\\' + self.curr_apk.apk_path[
                                                            self.curr_apk.apk_path.rfind('\\') + 1:] + '\\'
            else:
                screenshot_path = self.temp_path + '\\' + self.curr_apk.apk_path[
                                                          self.curr_apk.apk_path.rfind('\\') + 1:] + '\\'
            self.atx.screenshot(screenshot_path + time_name + '.png')
            logging.info('Take screenshot success !')
            return screenshot_path + time_name + '.png'
        except:
            logging.info('Take screenshot fail !')

    def delete_file(self, path):
        os.remove(path)

    def click_back(self):
        self.atx.adb_shell(['input', 'keyevent', '4'])
        logging.info('CLICK BACK !')
        time.sleep(self.click_delay)
        events = {'action': 'CLICK', 'position': 'BACK'}
        current_screen_shot = self.take_screenshot()
        previous_state = self.curr_apk.state_stack[-1]
        previous2_state = self.curr_apk.state_stack[-2]
        previous_state_sh = previous_state.screen_shot
        previous2_state_sh = previous2_state.screen_shot
        cmp_p = ip.compare_two_image(previous_state_sh, current_screen_shot)
        cmp_p2 = ip.compare_two_image(previous2_state_sh, current_screen_shot)
        if cmp_p == True:
            # BACK INVALID
            logging.info('BACK INVALID ! !')
            self.delete_file(current_screen_shot)
            return 0
        elif cmp_p2 == True:
            # BACK SUCCESS
            logging.info('BACK SUCCESS ! !')
            self.curr_apk.utg.add_transition(previous_state, previous2_state, events)
            self.curr_apk.state_stack.append(previous2_state)
            return 1
        elif cmp_p2 == False:
            # BACK TO NEW STATE
            logging.info('BACK TO NEW STATE ! !')
            self.new_state_reached(previous_state, current_screen_shot, events)
            return 2

    def click_general(self, position):
        self.atx.click(position[0], position[1])
        logging.info('CLICK %d,%d !', position[0], position[1])
        time.sleep(self.click_delay)
        events = {'action': 'CLICK', 'position': position}
        previous_state, current_screen_shot = self.is_valid_action()
        if previous_state != None:
            logging.info('CLICK VALID ! NEW STATE REACHED !')
            self.new_state_reached(previous_state, current_screen_shot, events)
            return True
        else:
            logging.info('CLICK INVALID ! !')
            self.delete_file(current_screen_shot)
            return False

    def new_state_reached(self, previous_state, current_screenshot, events):
        current_state = self.create_state_via_screenshot(current_screenshot)
        current_state.fill_position_dict(self.match_image(current_state))
        self.curr_apk.utg.add_transition(previous_state, current_state, events)
        self.curr_apk.state_stack.append(current_state)
        self.curr_apk.state_list.append(current_state)

    def create_state_via_screenshot(self, screenshot):
        return State(self.curr_apk.apk_name, screenshot)

    def get_previous_state(self):
        return self.curr_apk.state_stack[-1]

    def is_valid_action(self):
        previous_state = self.get_previous_state()
        previous_screen_shot = previous_state.screen_shot
        current_screen_shot = self.take_screenshot()
        cmp = ip.compare_two_image(previous_screen_shot, current_screen_shot)
        if cmp:
            return None, current_screen_shot
        return previous_state, current_screen_shot

    def match_image(self, state=None):
        # template = state.screen_shot
        # img_dict = self.curr_apk.image_dict
        pos_dict = {}
        self.atx.keep_screen()
        for image in self.curr_apk.image_dict.keys():
            logging.info(image)
            match = None
            try:
                match = self.atx.match(image, method='sift')
            except:
                logging.error('CV error !')
            if match != None:
                threshold = match.confidence[0] * 1.0 / match.confidence[1]
            if match != None and threshold >= 0.5 and match.pos[0] <= self.device_resolution[0] and match.pos[1] <= \
                    self.device_resolution[0]:
                pos_dict[(image, match.pos[0], match.pos[1])] = 0
        self.atx.free_screen()
        logging.info('MATCH RESULT : %d', len(pos_dict))
        # dict - > {(img_name,pos1,pos2),0} 0/wait for click 1/clicked  chosen
        # dict - > {(img_name),(pos1,pos2,0)} 0/wait for click 1/clicked
        # shuffle dict : not here ??
        return pos_dict

    def output_result(self, state_info, trans_info):
        with open(self.result_path + '\\' + self.curr_apk.apk_path[
                                            self.curr_apk.apk_path.rfind('\\') + 1:] + '\\transition.json',
                  'w') as json_file:
            for ii in trans_info:
                for k, v in ii.items():
                    json_file.write(str(k) + ':' + str(v) + '\n')
                json_file.write('\n')
        with open(self.result_path + '\\' + self.curr_apk.apk_path[
                                            self.curr_apk.apk_path.rfind('\\') + 1:] + '\\state.json',
                  'w') as json_file1:
            for state in state_info:
                json_file1.write("time_name" + ':' + state["time_name"] + '\n')
                json_file1.write("md5_name" + ':' + state["md5_name"] + '\n')
                for k, v in state["image_match"].items():
                    json_file1.write(str(k) + ',' + str(v) + '\n')
                json_file1.write('\n')
